home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d2
/
zapscrn.arc
/
ZAP.ASM
< prev
next >
Wrap
Assembly Source File
|
1989-03-11
|
18KB
|
586 lines
page 60,132
; Copyright (C) 1988 Mark Adler Pasadena, CA
; All rights reserved.
title ZAP - screen saver for the EGA or VGA
comment #
Version history -
1.0 18 Nov 1988 First public version
1.1 14 Dec 1988 Fixed bug in EGAZAP
ZAP -
ZAP is a resident utility that blanks the screen after a specified
period of inactivity. The ZAP.ASM program actually generates two
different programs depending on the assembler options: EGAZAP and
VGAZAP. The first is for the IBM Enhanced Graphics Adapter or
compatibles, and the second is for IBM PS/2's, the IBM Video Graphics
Adpater, and comaptibles. From here on, ZAP will be used to mean
EGAZAP or VGAZAP, whichever is appropriate for your hardware.
To install ZAP, simply put the command ZAP in your AUTOEXEC.BAT file.
From then on, when there is five minutes of inactivity at the
keyboard, ZAP will blank the screen until any key (even just a shift
key) is hit. The time can be changed with a command line option which
specifies the time in seconds. For example:
zap 600
will install ZAP (if not already installed) and change the time to 10
minutes.
You can also turn the installed ZAP on and off using ZAP. For example:
zap off
will turn off the installed ZAP, so it will not blank the screen. Then
the command:
zap on
will turn ZAP back on.
ZAP can also be installed in the "off" state, awaiting a "zap on"
command, simply by using:
zap off
in AUTOEXEC.BAT. You can also specify on or off along with a new
inactivity time. For example, the command:
zap off 600
in AUTOEXEC.BAT will install ZAP in the off state with a 10 minute
inactivity time. Then a subsequent "zap on" will turn it on. The time
must be in the range of one to 3600 seconds (one hour). Specifying a
new time does not change whether ZAP is enabled or not and turning ZAP
on or off does not change the time. Also, the two options can be in
either order. For example, "zap 600 off" does the same thing as the
example above. If ZAP is already installed, subsequent invocations of
ZAP will not install it again. If the command:
zap
is entered after ZAP is already installed, this has the same effect as
the command "zap on", that is it turns on ZAP if it was off.
ZAP turns the display back on not only when any key is hit, but also if
any video BIOS calls (int 10h) are made. Since most application
programs seem to bypass the BIOS for video, this added feature has
little effect.
There are a few, rare programs that also completely take the keyboard
from the BIOS, in which case ZAP can no longer find out when keystrokes
occur. An example is STSC APL (a programming language). In this case,
ZAP will blank your display, even though you have been merrily typing
away for the last five minutes in the application. And the only way to
get the display back on is to return to DOS (assuming you can get out
while driving the application blindfolded). For such applications, you
should include the commands "zap off" and "zap on" in a batch file that
runs the application to disable ZAP before entering and enabling ZAP
after leaving the application. You will quickly discover if you have
any such applications.
This program assumes that the current display is the (only) active
display, but does not check for it either at installation or when
running.
For the EGA, the screen is blanked by setting the number of characters
displayed to one, and the start of horizontal blanking to the first
character. The number of displayed characters needs to be small (set
to one for convenience) since the horizontal blanking interval is
limited to 32 characters. The screen is restored by getting the
current screen mode information from the BIOS and from that and the
table of Start Horizontal Blanking values in this program (copied from
the BIOS listing---not entirely kosher, but the only decent approach),
the proper register values are restored.
For the VGA, the screen is blanked and restored using the Screen Off
bit in the Clocking Mode Register (port 0x3c4, address 01, bit 5).
To minimize the resident memory required, this program is assembled
separately for the EGA or VGA. When assembling, define the symbol EGA
or VGA in the command line using /d (see the manual for MASM or TASM).
If no symbol is defined, you will be warned and the resulting .COM file
will be asssembled for the VGA. For example, the commands:
tasm /dega zap
tlink /t zap,egazap
tasm /dvga zap
tlink /t zap,vgazap
will generate EGAZAP.COM and VGAZAP.COM, assuming that you have the
Borland Turbo Assembler.
The fact that the number of bytes in VGAZAP (666) is the same as
Reagan's retirement home's address in Bel Air should be given no
religious significance.
#
ifndef VGA
ifndef EGA
%out !No display specified---assembling for the VGA.
endif
endif
;
; Macros for blanking screens.
;
egaoff macro
local ismono,CRTMON,CRTCOL
CRTMON equ 03B4h ;;CRT controller register in Mono mode.
CRTCOL equ 03D4h ;;CRT controller register in Color mode.
push AX ;;Save registers.
push BX
push CX
push DX
mov AH,12h ;;Get Mono/Color in BH.
mov BL,10h
pushf ;;Do Int 10h
push CS
call altvid
mov DX,CRTMON ;;Point DX to CRT port in Mono mode.
test BH,BH ;;See if color mode.
jnz ismono ;;If not, then DX is correct.
mov DX,CRTCOL ;;If color, use color address.
ismono:
mov AX,1 ;;Set number of characters to 1.
out DX,AX
inc AX ;;Set horizontal start of blanking to char 0.
out DX,AX
pop DX ;;Restore registers.
pop CX
pop BX
pop AX
endm
egaon macro
local ismono,enhance,shbget,tbl,CRTMON,CRTCOL
CRTMON equ 03B4h ;;CRT controller register in Mono mode.
CRTCOL equ 03D4h ;;CRT controller register in Color mode.
;;
;; Restore the display by getting the correct register values and
;; setting them.
;;
;; save registers used by routine, except AX.
push BX
push CX
push DX
;; get CRT port, switch setting.
mov AH,12h ;;Get switch setting into CL, Mono/Color in BH.
mov BL,10h
pushf ;;Do Int 10h
push CS
call altvid
mov DX,CRTMON ;;Point DX to CRT port in Mono mode.
test BH,BH ;;See if color mode.
jnz ismono ;;If not, then DX is correct.
mov DX,CRTCOL ;;If color, use color address.
ismono:
;; get values for CRT registers 1 and 2.
mov AH,0Fh ;;Get mode into AL, columns into AH.
pushf ;;Do Int 10h
push CS
call altvid
dec AH ;;Compute Horizontal Display End setting (1).
cmp AL,3 ;;See if color mode.
ja shbget ;;If not, go on to get Start Horiz Blank (2).
cmp CL,3 ;;See if in secondary enhanced mode.
je enhance ;;If so, use enhanced 0-3 settings.
cmp CL,9 ;;See if in primary enhanced mode.
jne shbget ;;If not, use normal 0-3 settings.
enhance:
add AL,11h ;;Add offset for table.
shbget:
mov BX,(offset trap)+(tbl-set) ;;Point to table.
xlat byte ptr CS:tbl ;;Get Start Horizontal Blank setting.
;; Now AH is CRT register 1, AL is register 2 - set them.
mov CL,AL ;;Save register 2 setting.
mov AL,1 ;;Set register 1.
out DX,AX
mov AH,CL ;;Get register 2 setting.
inc AX ;;Set register 2.
out DX,AX
;; done, restore registers and return.
pop DX
pop CX
pop BX
ret
;;Start horiz blank values for modes 0-10, 0*-3*.
tbl label byte
db 2Dh,2Dh,5Ch,5Ch,2Dh,2Dh,59h,56h ;;0-7.
db 2Dh,2Dh,2Dh,5Ch,56h,2Dh,59h,56h,53h ;;8-10h.
db 2Bh,2Bh,53h,53h ;;0*-3*.
endm
vgaoff macro
local CRTSEQ
CRTSEQ equ 03C4h ;;CRT Sequencer register set.
push AX ;;Save registers.
push DX
mov DX,CRTSeq ;;Sequencer registers.
mov AL,1 ;;Point to Clocking Mode register.
out DX,AL
inc DX
in AL,DX ;;Get current value.
or AL,020h ;;Turn on Screen Off bit.
out DX,AL
pop DX ;;Restore registers.
pop AX
endm
vgaon macro
local CRTSEQ
CRTSEQ equ 03C4h ;;CRT Sequencer register set.
;; save registers used by routine, except AX.
push DX
;; turn Screen Off bit off.
mov DX,CRTSEQ ;;Sequencer registers.
mov AL,1 ;;Point to Clocking Mode register.
out DX,AL
inc DX
in AL,DX ;;Get current value.
and AL,0DFh ;;Turn off Screen Off bit.
out DX,AL
;; done, restore registers and return.
pop DX
ret
endm
;
; Interrupt vector segment definitions.
;
ints segment at 0
dummy label far
org 8*4 ;Point to Int 8 (tick) vector.
int8 label word
org 9*4 ;Point to Int 9 (scan) vector.
int9 label word
org 10h*4 ;Point to Int 10h (video) vector.
int10 label word
ints ends
;
; Program segment.
;
zap segment
assume CS:zap,DS:zap,ES:zap,SS:zap
;
; Put service code as low as DOS will allow.
org 5Ch
time dw ? ;Time before blanking in ticks.
count dw ? ;Tick countdown.
trap label word ;Location for interrupt traps.
;
; Partially parsed command line.
org 5Ch
f1 db 12 dup(?)
org 6Ch
f2 db 12 dup(?)
;
; Constants.
DTIME equ 5462 ;Default time of about five minutes.
;
; Start of .COM code - jump to installation.
org 100h
start:
jmp cpyrt
db 13,'ZAP version 1.0 Copyright (C) 1988 Mark Adler',13,10
db 'All rights reserved.',13,10,'Z'-64
cpyrt:
;
; process arguments.
cld ;This stays in effect for the whole program.
mov onoff,1 ;Set ZAP to on.
mov id,'Z' ;So we don't find COM file in a buffer.
mov BX,offset f1
call chknon ;See if no arg.
je afin
call chkoff ;Have first arg---see if on or off.
je do2
call chknum ;Not on or off---see if number.
jz erra ;If no number there, then bad args.
do2:
mov BX,offset f2
call chknon ;See if second arg.
je afin
call chkoff ;Have second arg---see if on or off.
je aok
call chknum ;Not on or off---see if number.
jz erra ;If no number there, then bad args.
aok:
afin:
; look to see if ZAP is installed yet.
mov DX,DS ;Start checking backwards from this segment.
assume ES:nothing
search:
dec DX
jz nowhere ;If at bottom of memory, then it ain't loaded.
mov SI,offset id ;Point DS:SI to id string to look for.
mov ES,DX ;Point ES:DI to where to look.
sub DI,DI ;The id string should be on a 16 byte boundary.
mov CX,idlen
repe cmpsb
jne search ;If no match, look one back.
; now ES:DI point to byte after id.
mov AL,onoff ;Set enable byte of ZAP.
stosb
add DI,16-(1+idlen+4) ;Point to time and count.
dec DX
mov ES,DX
mov AX,newtime ;Get time setting.
test AX,AX ;See if it is a new setting.
jnz usenew
mov AX,ES:[DI] ;If no new setting, use old setting.
usenew:
stosw
stosw ;Reset count as well.
mov AH,0Fh ;Turn display on in case it's off.
int 10h ;(dummy int 10 call.)
int 20h ;Done.
; ZAP not installed---install with specified options.
nowhere:
mov AX,DS ;Restore ES.
mov ES,AX
assume ES:zap
mov AL,onoff ;Get on/off setting.
mov enbl,AL ;Put in enbl flag in traps before moving.
mov AX,newtime ;Set time and count.
test AX,AX
jnz timok
mov AX,DTIME ;Get default time (five minuntes).
timok:
mov time,AX
mov count,AX
jmp copy ;Go set up traps and stay resident.
erra:
mov DX,offset err2
jmp short errx
chknon proc near
mov SI,BX
mov DI,offset snone
mov CX,6
repe cmpsw
ret
chknon endp
chkoff proc near
; Compare [BX] with soff and son, return NE if neither match.
mov SI,BX
mov DI,offset soff
mov CX,6
repe cmpsw
jne noff
mov onoff,0
ret
noff:
mov SI,BX
mov DI,offset son
mov CX,6
repe cmpsw
ret
chkoff endp
chknum proc near
lea SI,[BX+1] ;Point to arg (BX loaded already).
sub BX,BX ;Initial value.
mov DI,10 ;Base for decimal.
mov CX,8 ;Digits allowed in name.
numlp:
lodsb
sub AL,'0'
jb nend
cmp AL,9
ja nend
cbw
xchg AX,BX
mul DI
add BX,AX
loop numlp
nend:
test BX,BX ;See if got a value.
jz nret ;If not, just return.
mov AX,91 ;Multiply by 18.2.
mul BX
shr DI,1 ;Put 5 in DI.
cmp DX,DI
jae errn ;If number of seconds too high, then error.
div DI ;18.2 = 91/5.
cmp DX,3 ;See if need to round up.
jb rdown ;If remainder 0, 1, or 2, then round down.
inc AX ;Else, round up.
rdown:
mov newtime,AX ;(Note, Z flag is false here.)
nret:
ret ;Return NZ if got a valid time.
chknum endp
errn:
mov DX,offset err1
errx:
mov AH,9
int 21h
int 20h
err1 db '?Seconds out of range---must be in 1..3600',13,10,'$'
err2 db '?Invalid argument---can be "on", "off", or time'
db 10,13,'$'
soff db 0,'OFF '
son db 0,'ON '
snone db 0,' '
newtime dw 0
onoff db 1
;
; Traps - only assume CS points here.
assume DS:nothing,ES:nothing,SS:nothing
set: ;Traps.
id db ' APTSR'
idlen equ $-id
enbl db 1 ;Enable flag.
tick:
;
; Timer tick action - if tick count not at already at zero, decrement
; it. If this makes the count zero, blank the screen.
;
cmp byte ptr trap+(enbl-set),1 ;See if enabled.
jne tfin ;If not, skip this.
cmp count,0 ;See if count at zero.
je tfin ;If so, don't decrement.
dec count ;Decrement tick count.
jnz tfin ;Wait until counts down to zero.
; disable display.
ifdef EGA
egaoff
else
vgaoff
endif
; go on to service routine.
tfin:
jmp dummy ;Go on to service routine.
tvec equ $-4 ;Address in jmp.
scan:
;
; Keyboard scan code action - reset the count to the maximum. If the
; count was zero, then the screen is blanked. In that case, restore
; the display.
;
push AX
cmp count,0 ;See if count at zero.
jne sfin ;If not, just reset count.
call don ;Display blanked - restore it.
sfin:
mov AX,time
mov count,AX ;Reset count.
pop AX
jmp dummy ;Go on to service routine.
svec equ $-4 ;Address in jmp.
vid:
;
; Video service request action - reset the count to the maximum. If
; the count was zero, then the screen is blanked. In that case,
; restore the display.
;
push AX
cmp count,0 ;See if count at zero.
jne vfin ;If not, just reset count.
call don ;Display blanked - restore it.
vfin:
mov AX,time
mov count,AX ;Reset count.
pop AX
altvid: ;(For using Int 10h within these routines.)
jmp dummy ;Go on to service routine.
vvec equ $-4 ;Address in jmp.
don:
ifdef EGA
egaon
else
vgaon
endif
setlen equ $-set ;End of traps.
;
; Installation code - all segment registers set.
assume DS:zap,ES:zap,SS:zap
copy:
;
; Install traps and tell DOS to leave them in memory.
;
; copy traps to lower memory.
mov SI,offset set
mov DI,offset trap
mov CX,setlen
rep movsb ;Assume direction flag cleared.
; set up to insert traps into interrupt vectors.
sub AX,AX
mov ES,AX ;Point to interrupt area.
assume ES:ints
cli ;Disable interrupts during change.
; insert trap in timer tick interrupt vector.
mov AX,int8 ;Get old vector.
mov trap+(tvec-set),AX ;Put in jump instruction.
mov AX,int8+2
mov trap+(tvec+2-set),AX
mov AX,offset trap+(tick-set)
mov int8,AX ;Change Int 8 to the trap.
mov AX,CS
mov int8+2,AX
; insert trap in keyboard scan code interrupt vector.
mov AX,int9 ;Get old vector.
mov trap+(svec-set),AX ;Put in jump instruction.
mov AX,int9+2
mov trap+(svec+2-set),AX
mov AX,offset trap+(scan-set)
mov int9,AX ;Change Int 9 to the trap.
mov AX,CS
mov int9+2,AX
; insert trap in video service interrupt vector.
mov AX,int10 ;Get old vector.
mov trap+(vvec-set),AX ;Put in jump instruction.
mov AX,int10+2
mov trap+(vvec+2-set),AX
mov AX,offset trap+(vid-set)
mov int10,AX ;Change Int 10h to the trap.
mov AX,CS
mov int10+2,AX
; tell DOS to keep the traps in memory and exit.
sti ;Interrupts OK now.
mov DX,offset trap+setlen ;Amount to keep.
int 27h ;Exit and remain resident.
zap ends
end start